package com.sound.ampache;

/* Copyright (c) 2010 Brian Kirkman <kirkman.brian@gmail.com>
*
* +------------------------------------------------------------------------+
* | This program is free software; you can redistribute it and/or          |
* | modify it under the terms of the GNU General Public License            |
* | as published by the Free Software Foundation; either version 3         |
* | of the License, or (at your option) any later version.                 |
* |                                                                        |
* | This program is distributed in the hope that it will be useful,        |
* | but WITHOUT ANY WARRANTY; without even the implied warranty of         |
* | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          |
* | GNU General Public License for more details.                           |
* |                                                                        |
* | You should have received a copy of the GNU General Public License      |
* | along with this program; if not, write to the Free Software            |
* | Foundation, Inc., 59 Temple Place - Suite 330,                         |
* | Boston, MA  02111-1307, USA.                                           |
* +------------------------------------------------------------------------+
*
* Special thanks to the following: 
* Kevin Purdy, author of Amdroid, for much of the code used in this project
* 
* Jorge Ramon, author of MiamiCoder blog, for many great BlackBerry examples
* published on his blog.
* 
* 
*/

import java.util.Timer;
import java.util.TimerTask;

import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.VolumeControl;

import net.rim.device.api.math.Fixed32;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Characters;
import net.rim.device.api.system.Display;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.system.KeyListener;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.DrawStyle;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.Screen;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.MainScreen;

import com.sound.ampache.streaming.StreamingPlayer;
import com.sound.ampache.streaming.StreamingPlayerListener;
import com.sound.ampache.streaming.UrlToImage;
import com.sound.ampache.objects.Song;

public class PlayerScreen extends MainScreen implements StreamingPlayerListener, KeyListener, TimeLineFieldListener {
	private StreamingPlayer sp;	
	private VolumeControl volC;	
	private int volLevel = 70;
	private PlayerScreen playerScreen;
	private long lastBufferUpdate = System.currentTimeMillis();
	
	private Song thisSong;
	private String url;
	private String urlAlbumArt;
	private String connTypeString;
	
	private String contentType = "audio/mpeg";
	private int bitRate = 128000;
	private int initBuffer = (bitRate/8)*5;	
	private int restartThreshold = (bitRate/8)*3;
	private int bufferCapacity = 4194304;
	private int bufferLeakSize = bufferCapacity/3;
	private int connectionTimeout = 6000;
	private boolean eventLogEnabled = false;
	private boolean sdLogEnabled = false;
	private int logLevel = 1;
	private boolean pauseState = false;
	
	
	private AlbumArtField albumArt;
	private AlbumInfoField albumInfo;
	private TimeLineField timeSeeker;
	
	
	private long bufferStartsAt = 0;
	private long len = 0;
	private String status = "Welcome!";
	private long nowPlaying = 0;
	
	private int screenWidth = Display.getWidth();
	private int screenHeight = Display.getHeight();
	
	private int artFieldHeight;
	private int artSize;
	private int timeFieldHeight;
	private int buttonFieldHeight;
	private int smallButtonFieldWidth;
	private int buttonHeight;
	private int smallButtonHeight;
	
	private boolean songIsPlaying;
	
	HorizontalFieldManager topAlbumField;
	HorizontalFieldManager middleTimeField;
	HorizontalFieldManager bottomButtonField;
	
	CustomThreeButton repeatButton;
	CustomSwapButton shuffleButton;
	CustomImgButton prevButton;
	CustomSwapButton playButton;
	CustomImgButton stopButton;
	CustomImgButton nextButton;
	CustomImgButton playlistButton;

	
	public PlayerScreen(){
		super(Screen.NO_HORIZONTAL_SCROLL|Screen.NO_VERTICAL_SCROLL);		
		this.playerScreen = this;	
		
		buttonFieldHeight = (int) Math.ceil(screenWidth / 6);
		buttonHeight = buttonFieldHeight - 4;
		smallButtonFieldWidth = (int) Math.floor((buttonFieldHeight *2) / 3);
		smallButtonHeight = smallButtonFieldWidth - 4;
		
		timeFieldHeight = 22;
		
		artFieldHeight = screenHeight - buttonFieldHeight - timeFieldHeight; 
		artSize = Math.min(artFieldHeight - 8, Display.getWidth() / 2 - 8);
		
		timeSeeker = new TimeLineField(Display.getWidth(), timeFieldHeight, 3);
		timeSeeker.addTimeLineFieldListener(this);
		
		albumArt = new AlbumArtField();
		albumInfo = new AlbumInfoField();
		
		topAlbumField = new HorizontalFieldManager();
		middleTimeField = new HorizontalFieldManager();
		bottomButtonField = new HorizontalFieldManager();
		
		
		add(topAlbumField);
		add(middleTimeField);
		add(bottomButtonField);
		
		topAlbumField.add(albumArt);
		topAlbumField.add(albumInfo);
		middleTimeField.add(timeSeeker);
		
		
		repeatButton = new CustomThreeButton("mp_repeat_no_light.jpg", "mp_repeat_no.jpg", 
				"mp_repeat_all_light.jpg", "mp_repeat_all.jpg",
				"mp_repeat_1_light.jpg", "mp_repeat_1.jpg",
				smallButtonFieldWidth, buttonFieldHeight, smallButtonHeight, 
				smallButtonHeight, 2, buttonFieldHeight - smallButtonHeight - 3);
		shuffleButton = new CustomSwapButton("mp_shuffle_no_light.jpg", "mp_shuffle_no.jpg",
				"mp_shuffle_light.jpg", "mp_shuffle.jpg",
				smallButtonFieldWidth, buttonFieldHeight, smallButtonHeight,
				smallButtonHeight, 2, buttonFieldHeight - smallButtonHeight - 3);
		prevButton = new CustomImgButton("mp_prev_light.jpg", "mp_prev.jpg", 
				buttonFieldHeight, buttonFieldHeight, buttonHeight, buttonHeight, 2, 2);
		playButton = new CustomSwapButton("mp_play_light.jpg", "mp_play.jpg", "mp_pause_light.jpg", 
				"mp_pause.jpg", buttonFieldHeight, buttonFieldHeight, buttonHeight, buttonHeight, 2, 2);
		stopButton = new CustomImgButton("mp_stop_light.jpg", "mp_stop.jpg", 
				buttonFieldHeight, buttonFieldHeight, buttonHeight, buttonHeight, 2, 2);
		nextButton = new CustomImgButton("mp_next_light.jpg", "mp_next.jpg", 
				buttonFieldHeight, buttonFieldHeight, buttonHeight, buttonHeight, 2, 2);
		playlistButton = new CustomImgButton("mp_playlist_light.jpg", "mp_playlist.jpg", 
				smallButtonFieldWidth + 4, buttonFieldHeight, smallButtonHeight, 
				smallButtonHeight, 2, buttonFieldHeight - smallButtonHeight - 3);
		
		
		FieldChangeListener shuffleListener = new FieldChangeListener() { 
			public void fieldChanged(Field field, int context) { 
				shuffleSongs();
			} 
		}; 
		
		
		FieldChangeListener repeatListener = new FieldChangeListener() { 
			public void fieldChanged(Field field, int context) { 
				repeatSongs();
			} 
		}; 
		
		
		FieldChangeListener prevListener = new FieldChangeListener() { 
			public void fieldChanged(Field field, int context) { 
				prevSong();
			} 
		}; 
		
		
		FieldChangeListener playListener = new FieldChangeListener() { 
			public void fieldChanged(Field field, int context) { 
				playPause();
			} 
		}; 
		
		
		FieldChangeListener stopListener = new FieldChangeListener() { 
			public void fieldChanged(Field field, int context) { 
				stop();
			} 
		}; 
		

		FieldChangeListener nextListener = new FieldChangeListener() { 
			public void fieldChanged(Field field, int context) { 
				nextSong();
			} 
		}; 
		

		FieldChangeListener playlistListener = new FieldChangeListener() { 
			public void fieldChanged(Field field, int context) {
				playlistShow();
			} 
		}; 

		
		shuffleButton.setChangeListener(shuffleListener);
		repeatButton.setChangeListener(repeatListener);
		prevButton.setChangeListener(prevListener);
		playButton.setChangeListener(playListener);
		stopButton.setChangeListener(stopListener);
		nextButton.setChangeListener(nextListener);
		playlistButton.setChangeListener(playlistListener);

		
		bottomButtonField.add(shuffleButton);
		bottomButtonField.add(repeatButton);
		bottomButtonField.add(prevButton);
		bottomButtonField.add(playButton);
		bottomButtonField.add(stopButton);
		bottomButtonField.add(nextButton);
		bottomButtonField.add(playlistButton);
		
		playButton.setFocus();
		setConnType();
	}
	
	
	private void playPause() {
		if (nowPlaying == 0) {
			play();
			pauseState = false;
		} else {
			if (pauseState) {
				resume();
				pauseState = false;
			} else {
				pause();
				pauseState = true;
			}
		}
	}
	
	
	private void shuffleSongs() {
		if (ampacheberry.playlistSong.getRandom()) {
			shuffleButton.toggleImage1();
			ampacheberry.playlistSong.setRandom(false);
		} else {
			shuffleButton.toggleImage2();
			ampacheberry.playlistSong.setRandom(true);
		}
	}
	
	
	private void repeatSongs() {
		if (ampacheberry.playlistSong.getRepeatAll()) {
			ampacheberry.playlistSong.setRepeatAll(false);
			ampacheberry.playlistSong.setRepeatOne(true);
			repeatButton.toggleImage3();
		} else if (ampacheberry.playlistSong.getRepeatOne()) {
			ampacheberry.playlistSong.setRepeatOne(false);
			ampacheberry.playlistSong.setRepeatAll(false);
			repeatButton.toggleImage1();
		}  else {
			ampacheberry.playlistSong.setRepeatOne(false);
			ampacheberry.playlistSong.setRepeatAll(true);
			repeatButton.toggleImage2();
		}
	}
	
	
	private void playlistShow() {
		Integer playingIndex = ampacheberry.playlistSong.getPlayingSong();
		
		ampacheberry.playlistScreen.setHighligt(playingIndex.intValue());
		UiApplication.getUiApplication().pushScreen(ampacheberry.playlistScreen);
	}
	
	
	private void skipFF() {
		new Thread(){
			public void run(){
				try{
					sp.setMediaTime(sp.getMediaTime() + 5000000);
				} catch(MediaException me){
					
				}
			}
		}.start();
	}
	
	
	private void skipRW() {
		new Thread(){
			public void run(){
				try{
					sp.setMediaTime(sp.getMediaTime() - 5000000);
				} catch(MediaException me){
					
				}
			}
		}.start();
	}
	
	
	public void volUp() {
		if(volC!=null){
	    	volC.setLevel(volC.getLevel()+5);
	    	volLevel = volC.getLevel();
		}
	}
	
	public void volDown() {
		if(volC!=null){
	    	volC.setLevel(volC.getLevel()-5);
	    	volLevel = volC.getLevel();
		}
	}
	
	
	public void setConnType() {
		connTypeString = TransportUtils.getConnectionString();
	}
	
	public void play(){
		final Integer songToPlay = ampacheberry.playlistSong.getPlayingSong();
		if(songToPlay.intValue() != -1){
			new Thread(){
				public void run(){
					try{
						if(sp==null){
							//ping to keep the session alive
							ampacheberry.comm.ping();  //threaded
							songIsPlaying = true;
							thisSong = (Song) ampacheberry.playlistSong.songPlaylist.
								elementAt(songToPlay.intValue());
							url = thisSong.url + connTypeString;
							playButton.toggleImage2();
							setSongInfo();
							setSongArt(); //threaded
							sp = new StreamingPlayer(url, contentType);						
							sp.setBufferCapacity(bufferCapacity);						
							sp.setInitialBuffer(initBuffer);
							sp.setRestartThreshold(restartThreshold);
							sp.setBufferLeakSize(bufferLeakSize);
							sp.setConnectionTimeout(connectionTimeout);
							sp.setLogLevel(logLevel);
							sp.enableLogging(eventLogEnabled, sdLogEnabled);					
							sp.addStreamingPlayerListener(playerScreen);
							sp.realize();
							volC = (VolumeControl)sp.getControl("VolumeControl");
							volC.setLevel(volLevel);
							sp.start();
						}
						
					} catch(Throwable t){
						//log(t.toString());
					}
				}
			}.start();
		}
	}

	public void seek(final long position){		
		new Thread(){
			public void run(){
				try{
					sp.setMediaTime(position*1000000);
				} catch(MediaException me){
					
				}
			}
		}.start();
	}
	
	public void pause(){
		try{
			if(sp!=null){
				sp.stop();
				playButton.toggleImage1();
			}
		} catch(Throwable t){
			
		}
	}
	
	public void resume(){
		try{
			if(sp!=null){
				if(sp.getState()!=Player.STARTED){
					sp.start();
					playButton.toggleImage2();
				}
			}
		} catch(Throwable t){
			
		}
	}
	
	public void stop(){
		try{
			if(sp!=null){
				sp.close();
				timeSeeker.setBuffered(0, 0);
				timeSeeker.setTimeLength(0);
				timeSeeker.setContentLength(0);
				timeSeeker.setNow(0);
				timeSeeker.update();
				playButton.toggleImage1();
				sp.removeStreamingPlayerListener(playerScreen);
				sp = null;
				nowPlaying = 0;
				songIsPlaying = false;
				volC = null;
			}
		} catch(Throwable t){
			//log(t.toString());
		}
	}
	
	
	public void nextSong(){
		if (ampacheberry.playlistSong.getRepeatOne()) { //repeat song
			if (sp!=null) {
				seek(0);
			} else {
				stop();
				sp = null;
				play();
			}
		} else { //go next song
			ampacheberry.playlistSong.advanceSong();
			if (!ampacheberry.playlistSong.getEndOfPlaylist()) { //not at end of playlist or repeat all
				stop();
				sp = null;
				play();
			}
		}
	}
	
	
	public void prevSong(){
		//restart song if song has been playing for more than three seconds
		if (nowPlaying > 3) {
			seek(0);
		} else {
			ampacheberry.playlistSong.backSong();
			if (!ampacheberry.playlistSong.getStartOfPlaylist()){
				stop();
				sp = null;
				play();
			}
		}
	}
	
	
	public void setSongInfo() {
		albumInfo.setInfo();
	}
	
	
	public void setSongArt() {
		albumArt.setAlbumArt();
	}
	
	
	/** StreamingPlayerListener Implementation */
	public void bufferStatusChanged(long bufferStartsAt, long len) {
		this.bufferStartsAt = bufferStartsAt;
		this.len = len;		
		
		boolean update = (System.currentTimeMillis()-lastBufferUpdate)>25;
		if(!update)
			return;
		lastBufferUpdate = System.currentTimeMillis();		
		
		timeSeeker.setBuffered(bufferStartsAt, len);
		timeSeeker.setNow(nowPlaying);
		timeSeeker.setStatus(this.status);		
		timeSeeker.update();
	}

	public void downloadStatusUpdated(final long totalDownloaded) {		
									
	}

	public void feedPaused(final long available) {
		this.status = "Buffering..";
		
		boolean update = (System.currentTimeMillis()-lastBufferUpdate)>25;
		if(!update)
			return;
		lastBufferUpdate = System.currentTimeMillis();
		
		timeSeeker.setBuffered(bufferStartsAt, len);
		timeSeeker.setNow(nowPlaying);
		timeSeeker.setStatus(this.status);	
		timeSeeker.update();
	}

	public void feedRestarted(final long available) {
		this.status = "Reading..";
		
		boolean update = (System.currentTimeMillis()-lastBufferUpdate)>25;
		if(!update)
			return;
		lastBufferUpdate = System.currentTimeMillis();		
		
		timeSeeker.setBuffered(bufferStartsAt, len);
		timeSeeker.setNow(nowPlaying);
		timeSeeker.setStatus(this.status);	
		timeSeeker.update();
	}

	public void initialBufferCompleted(final long available) {
		this.status = "Reading..";
		
		boolean update = (System.currentTimeMillis()-lastBufferUpdate)>25;
		if(!update)
			return;
		lastBufferUpdate = System.currentTimeMillis();		
		
		timeSeeker.setBuffered(bufferStartsAt, len);
		timeSeeker.setNow(nowPlaying);
		timeSeeker.setStatus(this.status);	
		timeSeeker.update();
	}

	public void playerUpdate(String event, Object eventData) {
		if(event.equals(PlayerListener.END_OF_MEDIA)){
			if (ampacheberry.playlistSong.getRepeatOne()) { //repeat song
				stop();
				sp = null;
				play();
			} else {
				stop();
				sp = null;
				nextSong();
				Dialog.alert("ENDof SONG");
			}
		} else if(event.equalsIgnoreCase(PlayerListener.ERROR)){
			Dialog.inform(event+ ": " + eventData);
		}
	}

	public byte[] preprocessData(byte[] bytes, int off, int len) {	
		return null;		
	}
	
	public void nowReading(long now) {
		
		boolean update = (System.currentTimeMillis()-lastBufferUpdate)>25;
		if(!update)
			return;
		lastBufferUpdate = System.currentTimeMillis();		
			
		timeSeeker.setBuffered(bufferStartsAt, len);
		timeSeeker.setNow(nowPlaying);
		timeSeeker.setStatus(this.status);	
		timeSeeker.update();
	}
	
	public void nowPlaying(long now){
		this.nowPlaying = now/1000000;
		
		boolean update = (System.currentTimeMillis()-lastBufferUpdate)>25;
		if(!update)
			return;
		lastBufferUpdate = System.currentTimeMillis();
		
		timeSeeker.setBuffered(bufferStartsAt, len);
		timeSeeker.setNow(nowPlaying);
		timeSeeker.setStatus(this.status);	
		timeSeeker.update();
	}	

	
	public void contentLengthUpdated(long contentLength){  //BK check here
		timeSeeker.setTimeLength(sp.getDuration()/1000000);
		timeSeeker.setContentLength(contentLength);
	}	
	
	public void streamingError(final int code){
		UiApplication.getUiApplication().invokeLater(new Runnable(){
			public void run(){
				switch(code){
					case StreamingPlayerListener.ERROR_DOWNLOADING:
						timeSeeker.setStatus("An error occured while downloading..");
						break;
					case StreamingPlayerListener.ERROR_SEEKING:
						timeSeeker.setStatus("Error seeking..");
						break;
					case StreamingPlayerListener.ERROR_OPENING_CONNECTION:
						timeSeeker.setStatus("Error openning connection..");
						break;
					case StreamingPlayerListener.ERROR_PLAYING_MEDIA:
						timeSeeker.setStatus("Error Playing Media..Closed!");
						break;
				} 
				
			}
		});
	}
		
	private class AlbumArtField extends Field{
		Bitmap bitmap;

		public AlbumArtField(){			
			this.setAlbumArt();
		}
		
		protected void layout(int width, int height) {			
			setExtent(Display.getWidth() / 2, artFieldHeight);
			timeSeeker.setWidth(Display.getWidth());							
		}

		protected void paintBackground(Graphics graphics) {				
			super.paintBackground(graphics);			
			graphics.setColor(Color.BLACK);
			graphics.fillRect(0, 0, getWidth(), getHeight());
		}				
		
		protected void paint(Graphics graphics){
			if(bitmap!=null) {
				graphics.drawBitmap(((getWidth()-bitmap.getWidth())/2), (getHeight()/2)-(bitmap.getHeight()/2), bitmap.getWidth(), bitmap.getHeight(), bitmap, 0, 0);
			} else {
				bitmap = Bitmap.getBitmapResource("amdroid_icon.png");
				graphics.drawBitmap(((getWidth()-bitmap.getWidth())/2), (getHeight()/2)-(bitmap.getHeight()/2), bitmap.getWidth(), bitmap.getHeight(), bitmap, 0, 0);
			}
		}
		
		public void setAlbumArt(){
			if(ampacheberry.playlistSong.playedSongs.size() > 0) {
				Integer songToPlay = ampacheberry.playlistSong.getPlayingSong();
				thisSong = (Song) ampacheberry.playlistSong.songPlaylist.
										elementAt(songToPlay.intValue());
				
				//Only get album art if it is different from current
				if (urlAlbumArt != thisSong.art + connTypeString) {
					urlAlbumArt = thisSong.art + connTypeString;
					UrlToImage img = new UrlToImage(urlAlbumArt, artSize, artSize);
					bitmap = img.getbitmap();
				}
			} else {
				bitmap = null;
			}
			
			invalidate();
		}	
	}
	
	
	private class AlbumInfoField extends Field{
		String songTitle;
		String songArtist;
		String songAlbum;
		String scrollSongTitle;
		String scrollSongArtist;
		String scrollSongAlbum;
		private Timer _scrollTimer;
		private TimerTask _scrollTimerTask;
		
		int songTitleChar = 0;
		int songArtistChar = 0;
		int songAlbumChar = 0;
		
		int titleDraw;
		int artistDraw;
		int albumDraw;
		
		boolean titleScroll;
		boolean artistScroll;
		boolean albumScroll; 
		
		Font titleFont;
		Font artistFont;
		Font albumFont;
		
		
		public AlbumInfoField(){
			titleDraw = DrawStyle.HCENTER;
			artistDraw = DrawStyle.HCENTER;
			albumDraw = DrawStyle.HCENTER;
			titleFont = Font.getDefault().derive(Font.PLAIN, 18);
			artistFont = Font.getDefault().derive(Font.PLAIN, 14);
			albumFont = Font.getDefault().derive(Font.PLAIN, 14);
			this.setInfo();
		}
		
		protected void layout(int width, int height) {			
			setExtent(Display.getWidth() / 2, artFieldHeight);
		}

		protected void paintBackground(Graphics graphics) {				
			super.paintBackground(graphics);			
			graphics.setColor(Color.BLACK);
			graphics.fillRect(0, 0, getWidth(), getHeight());
		}				
		
		protected void paint(Graphics graphics){

			graphics.setColor(Color.WHITE);
			
			graphics.setFont(titleFont);
			graphics.drawText(scrollSongTitle, 5, (getHeight()/2) - 20, titleDraw, getWidth()-10);
			
			graphics.setFont(artistFont);
			graphics.drawText(scrollSongArtist, 5, (getHeight()/2), artistDraw, getWidth()-10);
			
			graphics.setFont(albumFont);
			graphics.drawText(scrollSongAlbum, 5, (getHeight()/2) + 16, albumDraw, getWidth()-10);
		}
		
		
		
		public void setInfo(){
			if(ampacheberry.playlistSong.playedSongs.size() > 0) {
				Integer songToPlay = ampacheberry.playlistSong.getPlayingSong();
				thisSong = (Song) ampacheberry.playlistSong.songPlaylist.
										elementAt(songToPlay.intValue());
				songTitle = thisSong.name;
				songArtist = thisSong.artist;
				songAlbum = thisSong.album;
			} else if(ampacheberry.playlistSong.playingSongs.size() > 0){
				songTitle = "Press Play To Start";
				songArtist = "-";
				songAlbum = "-";
			} else {
				songTitle = "No Songs";
				songArtist = "-";
				songAlbum = "-";
			}
			
			scrollSongTitle = songTitle;
			songTitleChar = 0;
			if(titleFont.getAdvance(songTitle) > Display.getWidth()/2-10){
				titleScroll = true;
				titleDraw = DrawStyle.LEFT;
			} else {
				titleScroll = false;
				titleDraw = DrawStyle.HCENTER;	
			}
			
			scrollSongArtist = songArtist;
			songArtistChar = 0;
			if(artistFont.getAdvance(songArtist) > Display.getWidth()/2-10){
				artistScroll = true;
				artistDraw = DrawStyle.LEFT;
			} else {
				artistScroll = false;
				artistDraw = DrawStyle.HCENTER;
			}
			
			scrollSongAlbum = songAlbum;
			songAlbumChar = 0;
			if(albumFont.getAdvance(songAlbum) > Display.getWidth()/2-10){
				albumScroll = true;
				albumDraw = DrawStyle.LEFT;
			} else {
				albumScroll = false;
				albumDraw = DrawStyle.HCENTER;
			}		
			
			invalidate();
			startScroll();
		}
				
		
		private void startScroll() {
			//Clear and stop timer
			if(_scrollTimer != null){
				_scrollTimer.cancel();
				_scrollTimerTask.cancel();
				_scrollTimer = null;
			}
			
			// Start scrolling
			if(titleScroll == true || artistScroll == true || albumScroll == true){
				if ( _scrollTimer == null ) {
					_scrollTimer = new Timer();
					_scrollTimerTask = new TimerTask() {
						public void run() {
							
							if(titleScroll == true){
								if (songTitleChar > songTitle.length()) {
									songTitleChar = 0;
									scrollSongTitle = songTitle;
								} else {
									scrollSongTitle = songTitle.substring(songTitleChar);
								}
								songTitleChar = songTitleChar + 4;
							}
							
							if(artistScroll == true){
								if (songArtistChar > songArtist.length()) {
									songArtistChar = 0;
									scrollSongArtist = songArtist;
								} else {
									scrollSongArtist = songArtist.substring(songArtistChar);
								}
								songArtistChar = songArtistChar + 4;
							}
							
							if(albumScroll == true){
								if (songAlbumChar > songAlbum.length()) {
									songAlbumChar = 0;
									scrollSongAlbum = songAlbum;
								} else {
									scrollSongAlbum = songAlbum.substring(songAlbumChar);
								}
								songAlbumChar = songAlbumChar + 4;
							}
							
							invalidate();
						}
					};
					_scrollTimer.scheduleAtFixedRate(_scrollTimerTask, 1500, 1500);
				}
			}
			
		}
		
	}
	
	
	public boolean keyChar(char key, int status, int time) {
        switch (key) {
	        case Characters.SPACE:
	        	playPause();
	        	return true;
	        case Characters.LATIN_SMALL_LETTER_X:
	        	stop();
	        	return true;
	        case Characters.LATIN_SMALL_LETTER_N:
	        	nextSong();
	        	return true;
	        case Characters.LATIN_SMALL_LETTER_P:
	        	prevSong();
	        	return true;
	        case Characters.LATIN_SMALL_LETTER_I:
	        	skipFF();
	        	return true;
	        case Characters.LATIN_SMALL_LETTER_O:
	        	skipRW();
	        	return true;
	        case Characters.LATIN_SMALL_LETTER_S:
	        	shuffleSongs();
	        	return true;
	        case Characters.LATIN_SMALL_LETTER_R:
	        	repeatSongs();
	        	return true;
	        case Characters.LATIN_SMALL_LETTER_L:
	        	playlistShow();
	        	return true;
	        case Characters.LATIN_SMALL_LETTER_U:
	        	volUp();
	        	return true;
	        case Characters.LATIN_SMALL_LETTER_D:
	        	volDown();
	        	return true;
        }
        return super.keyChar(key, status, time);
	}

	public boolean keyDown(int keycode, int time) {
		return false;
	}

	public boolean keyRepeat(int keycode, int time) {
		return false;		
	}

	public boolean keyStatus(int keycode, int time) {
		return false;
	}

	public boolean keyUp(int keycode, int time) {
		return false;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getContentType() {
		return contentType;
	}

	public void setContentType(String contentType) {
		this.contentType = contentType;
	}
	
	public boolean getSongIsPlaying() {
		return songIsPlaying;
	}
	
	public void setLogLevel(int level){
		this.logLevel = level;
	}
	
	public void setEventLogEnabled(boolean value){
		this.eventLogEnabled = value;
	}
	
	public void setSDLogEnabled(boolean value){
		this.sdLogEnabled = value;
	}
		
	public boolean getEventLogEnabled(){
		return this.eventLogEnabled;
	}
	
	public boolean getSDLogEnabled(){
		return this.sdLogEnabled;
	}

	public int getBitRate() {
		return bitRate;
	}

	public void setBitRate(int bitRate) {
		this.bitRate = bitRate;
	}

	public int getInitBuffer() {
		return initBuffer;
	}

	public void setInitBuffer(int initBuffer) {
		this.initBuffer = initBuffer;
	}

	public int getRestartThreshold() {
		return restartThreshold;
	}

	public void setRestartThreshold(int restartThreshold) {
		this.restartThreshold = restartThreshold;
	}

	public int getBufferCapacity() {
		return bufferCapacity;
	}

	public int getBufferLeakSize() {
		return bufferLeakSize;
	}

	public void setBufferLeakSize(int bufferLeakSize) {
		this.bufferLeakSize = bufferLeakSize;
	}

	public int getConnectionTimeout() {
		return connectionTimeout;
	}

	public void setConnectionTimeout(int connectionTimeout) {
		this.connectionTimeout = connectionTimeout;
	}

	public void setBufferCapacity(int bufferCapacity) {
		this.bufferCapacity = bufferCapacity;
	}

	public boolean onClose() {		
		Integer playingIndex = ampacheberry.playlistSong.getPlayingSong();
		ampacheberry.playlistScreen.setHighligt(playingIndex.intValue());
		
		return super.onClose();
	}

	protected boolean onSavePrompt() {
		return true;
	}
	

	
	//Custom private class that creates the button and switches the image depending
	//on the return value of onFocus()
	private class CustomImgButton extends Field implements DrawStyle{
	  
		private Bitmap _currentPicture;
		private Bitmap _onPicture; //image for "in focus"
		private Bitmap _offPicture; //image for "not in focus"
		private int imgWidth;
		private int imgHeight;
		private int fldWidth;
		private int fldHeight;
		private int xInt;
		private int yInt;
		CustomImgButton thisButton;
		
		 
		CustomImgButton (String onImage, String offImage, int fWidth, int fHeight, int iWidth, int iHeight, int x, int y){
			super();
			this.fldWidth = fWidth;
			this.fldHeight = fHeight;
			this.imgWidth = iWidth;
			this.imgHeight = iHeight;
			this.xInt = x;
			this.yInt = y;
			_onPicture = resizedImage(onImage, imgWidth, imgHeight);
			_offPicture = resizedImage(offImage, imgWidth, imgHeight);
			_currentPicture = _offPicture;         
		}
		
		protected Bitmap resizedImage (String imgPath, int iWidth, int iHeight){
			EncodedImage _pic = EncodedImage.getEncodedImageResource(imgPath);
			int currHeight = _pic.getHeight();
			int currWidth = _pic.getWidth();
			int multH= Fixed32.div(Fixed32.toFP(currHeight),Fixed32.toFP(iHeight));//height
			int multW = Fixed32.div(Fixed32.toFP(currWidth),Fixed32.toFP(iWidth));//width
			Bitmap rszBitmap = _pic.scaleImage32(multW,multH).getBitmap();
			
			return rszBitmap;
		}
		     
		 
		public boolean isFocusable(){
			return true;
		}
		     
		//Override function to switch picture
		protected void onFocus(int direction){
			_currentPicture = _onPicture;
			invalidate();
		}
		
		//Override function to switch picture
		protected void onUnfocus(){
			_currentPicture = _offPicture;
			invalidate();
		}
		     
		protected void layout(int width, int height) {
			setExtent(fldWidth, fldHeight);
		}
		  
		//update the fieldchange
		protected void fieldChangeNotify(int context) {
			try {
				this.getChangeListener().fieldChanged(this, context);
			} catch (Exception exception) {
			}
		}
		  
		//fill edges to match
		protected void paint(Graphics graphics) { 
			graphics.setColor(Color.BLACK); 
			graphics.fillRect(0, 0, getWidth(), getHeight());
			graphics.drawBitmap(xInt, yInt, imgWidth, imgHeight, _currentPicture, 0, 0);
		}
		
		 //Listen for navigation Click
		 protected boolean navigationClick(int status, int time){
			 fieldChangeNotify(1);
			 return true;
		 }
		 
	 }
	
	
	//Custom private class that creates the button and switches the image depending
	//on the return value of onFocus()
	private class CustomSwapButton extends Field implements DrawStyle{
	  
		private Bitmap _currentPicture;
		private Bitmap _onPicture; //image for "in focus"
		private Bitmap _offPicture; //image for "not in focus"
		private Bitmap _on1Picture; //image for "in focus"
		private Bitmap _off1Picture; //image for "not in focus"
		private Bitmap _on2Picture; //image for "in focus"
		private Bitmap _off2Picture; //image for "not in focus"
		private int imgWidth;
		private int imgHeight;
		private int fldWidth;
		private int fldHeight;
		private int xInt;
		private int yInt;
		private boolean picFocus;
		
		 
		CustomSwapButton (String on1Image, String off1Image, String on2Image, String off2Image, int fWidth, int fHeight, int iWidth, int iHeight, int x, int y){
			super();
			this.fldWidth = fWidth;
			this.fldHeight = fHeight;
			this.imgWidth = iWidth;
			this.imgHeight = iHeight;
			this.xInt = x;
			this.yInt = y;
			_on1Picture = resizedImage(on1Image, imgWidth, imgHeight);
			_off1Picture = resizedImage(off1Image, imgWidth, imgHeight);
			_on2Picture = resizedImage(on2Image, imgWidth, imgHeight);
			_off2Picture = resizedImage(off2Image, imgWidth, imgHeight);
			
			_onPicture = _on1Picture;  
			_offPicture = _off1Picture;  
			_currentPicture = _off1Picture; 
			picFocus = false;
		}
		
		protected Bitmap resizedImage (String imgPath, int iWidth, int iHeight){
			EncodedImage _pic = EncodedImage.getEncodedImageResource(imgPath);
			int currHeight = _pic.getHeight();
			int currWidth = _pic.getWidth();
			int multH= Fixed32.div(Fixed32.toFP(currHeight),Fixed32.toFP(iHeight));//height
			int multW = Fixed32.div(Fixed32.toFP(currWidth),Fixed32.toFP(iWidth));//width
			Bitmap rszBitmap = _pic.scaleImage32(multW,multH).getBitmap();
			
			return rszBitmap;
			
		}
		     
		 
		public boolean isFocusable(){
			return true;
		}
		     
		//Override function to switch picture
		protected void onFocus(int direction){
			_currentPicture = _onPicture;
			picFocus = true;
			invalidate();
		}
		
		
		//Override function to switch picture
		protected void onUnfocus(){
			_currentPicture = _offPicture;
			picFocus = false;
			invalidate();
			
		}
		     
		protected void layout(int width, int height) {
			setExtent(fldWidth, fldHeight);
		}
		  
		//update the fieldchange
		protected void fieldChangeNotify(int context) {
			try {
				this.getChangeListener().fieldChanged(this, context);
			} catch (Exception exception) {
			}
		}
		  
		//Since button is rounded we need to fill corners with dark color to match
		protected void paint(Graphics graphics) { 
			graphics.setColor(Color.BLACK); 
			graphics.fillRect(0, 0, getWidth(), getHeight());
			graphics.drawBitmap(xInt, yInt, imgWidth, imgHeight, _currentPicture, 0, 0);
		}
		 
		 
		 //Listen for navigation Click
		 protected boolean navigationClick(int status, int time){
			 fieldChangeNotify(1);
			return true;
		 }
		 
		 
		public void toggleImage1() {
			_onPicture = _on1Picture;  
			_offPicture = _off1Picture;
			
			if(picFocus == true){
				_currentPicture = _onPicture;
			} else {
				_currentPicture = _offPicture;
			}	
			
			invalidate();
		}
		 

		 public void toggleImage2() {
			_onPicture = _on2Picture;  
			_offPicture = _off2Picture; 
			
			if(picFocus == true){
				_currentPicture = _onPicture;
			} else {
				_currentPicture = _offPicture;
			}
			
			invalidate();
		}
		 
		 
	 }


	//Custom private class that creates the button and switches the image depending
	//on the return value of onFocus()
	private class CustomThreeButton extends Field implements DrawStyle{
	  
		private Bitmap _currentPicture;
		private Bitmap _onPicture; //image for "in focus"
		private Bitmap _offPicture; //image for "not in focus"
		private Bitmap _on1Picture; //image for "in focus"
		private Bitmap _off1Picture; //image for "not in focus"
		private Bitmap _on2Picture; //image for "in focus"
		private Bitmap _off2Picture; //image for "not in focus"
		private Bitmap _on3Picture; //image for "in focus"
		private Bitmap _off3Picture; //image for "not in focus"
		private int imgWidth;
		private int imgHeight;
		private int fldWidth;
		private int fldHeight;
		private int xInt;
		private int yInt;
		private boolean picFocus;
		
		 
		CustomThreeButton (String on1Image, String off1Image, String on2Image, String off2Image,
				String on3Image, String off3Image, int fWidth, int fHeight, 
				int iWidth, int iHeight, int x, int y) {
			super();
			this.fldWidth = fWidth;
			this.fldHeight = fHeight;
			this.imgWidth = iWidth;
			this.imgHeight = iHeight;
			this.xInt = x;
			this.yInt = y;
			_on1Picture = resizedImage(on1Image, imgWidth, imgHeight);
			_off1Picture = resizedImage(off1Image, imgWidth, imgHeight);
			_on2Picture = resizedImage(on2Image, imgWidth, imgHeight);
			_off2Picture = resizedImage(off2Image, imgWidth, imgHeight);
			_on3Picture = resizedImage(on3Image, imgWidth, imgHeight);
			_off3Picture = resizedImage(off3Image, imgWidth, imgHeight);
			
			_onPicture = _on1Picture;  
			_offPicture = _off1Picture;  
			_currentPicture = _off1Picture; 
			picFocus = false;
		}
		
		protected Bitmap resizedImage (String imgPath, int iWidth, int iHeight){
			EncodedImage _pic = EncodedImage.getEncodedImageResource(imgPath);
			int currHeight = _pic.getHeight();
			int currWidth = _pic.getWidth();
			int multH= Fixed32.div(Fixed32.toFP(currHeight),Fixed32.toFP(iHeight));//height
			int multW = Fixed32.div(Fixed32.toFP(currWidth),Fixed32.toFP(iWidth));//width
			Bitmap rszBitmap = _pic.scaleImage32(multW,multH).getBitmap();
			
			return rszBitmap;
			
		}
		     
		 
		public boolean isFocusable(){
			return true;
		}
		     
		//Override function to switch picture
		protected void onFocus(int direction){
			_currentPicture = _onPicture;
			picFocus = true;
			invalidate();
		}
		
		
		//Override function to switch picture
		protected void onUnfocus(){
			_currentPicture = _offPicture;
			picFocus = false;
			invalidate();
			
		}
		     
		protected void layout(int width, int height) {
			setExtent(fldWidth, fldHeight);
		}
		  
		//update the fieldchange
		protected void fieldChangeNotify(int context) {
			try {
				this.getChangeListener().fieldChanged(this, context);
			} catch (Exception exception) {
			}
		}
		  
		//Since button is rounded we need to fill corners with dark color to match
		protected void paint(Graphics graphics) { 
			graphics.setColor(Color.BLACK); 
			graphics.fillRect(0, 0, getWidth(), getHeight());
			graphics.drawBitmap(xInt, yInt, imgWidth, imgHeight, _currentPicture, 0, 0);
		}
		 
		 
		 //Listen for navigation Click
		 protected boolean navigationClick(int status, int time){
			 fieldChangeNotify(1);
			return true;
		 }
		 
		 
		public void toggleImage1() {
			_onPicture = _on1Picture;  
			_offPicture = _off1Picture;
			
			if(picFocus == true){
				_currentPicture = _onPicture;
			} else {
				_currentPicture = _offPicture;
			}	
			
			invalidate();
		}
		 

		 public void toggleImage2() {
			_onPicture = _on2Picture;  
			_offPicture = _off2Picture; 
			
			if(picFocus == true){
				_currentPicture = _onPicture;
			} else {
				_currentPicture = _offPicture;
			}
			
			invalidate();
		}
		 
		 public void toggleImage3() {
				_onPicture = _on3Picture;  
				_offPicture = _off3Picture; 
				
				if(picFocus == true){
					_currentPicture = _onPicture;
				} else {
					_currentPicture = _offPicture;
				}
				
				invalidate();
			}
		 
	 }	
	
}
